module Maze
  class Sigma < Generic
    OPPOSITE = { N => S, S => N, NE => SW, SW => NE, NW => SE, SE => NW }

    def random_directions
      [N, S, NE, NW, SE, SW].sort_by { rand }
    end

    alias_method :directions, :random_directions

    def opposite(direction)
      OPPOSITE[direction]
    end

    def calculate_offset_x_axis(*args)
      direction, point = args

      case direction
      when N, S
        0
      when NW, SW
        send("noexit_#{direction}?", point) ? 0 : -1
      when NE, SE
        send("noexit_#{direction}?", point) ? 0 : 1
      end
    end

    def calculate_offset_y_axis(*args)
      direction, point = args

      case direction
      when N
        noexit_north?(point) ? 0 : -1
      when S
        noexit_south?(point) ? 0 : 1
      when NW, NE
        send("noexit_#{direction}?", point) || shifted_down?(point) ? 0 : -1
      when SW, SE
        send("noexit_#{direction}?", point) || shifted_up?(point) ? 0 : 1
      end
    end

    def shifted_up?(point)
      0 == point.x % 2
    end

    def shifted_down?(point)
      !shifted_up?(point)
    end

    private

    def noexit_north?(point)
      0 == point.y
    end

    def noexit_south?(point)
      height - 1 == point.y
    end

    def noexit_west?(point)
      0 == point.x
    end

    def noexit_east?(point)
      width - 1 == point.y
    end

    def noexit_north_west?(point)
      noexit_west?(point) &&
        (noexit_north?(point) && shifted_up?(point))
    end

    def noexit_north_east?(point)
      noexit_east?(point) &&
        (noexit_north?(point) && shifted_up?(point))
    end

    def noexit_south_west?(point)
      noexit_west?(point) &&
        (noexit_south?(point) && shifted_down?(point))
    end

    def noexit_south_east?(point)
      noexit_east?(point) &&
        (noexit_south?(point) && shifted_down?(point))
    end
  end
end
